use serde::{Deserialize, Serialize};
use tokio_util::codec::{Decoder, Encoder};

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Params {
    pkg_header: Vec<u8>,
    pkg_seq: u8,
    equ_type: u8,
    equ_no: u8,
    msg_type: u8,
    msg_len: u8,
    pkg_body: PkgBody,
    check_sum: Vec<u8>,
    pkg_tail: Vec<u8>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PkgBody {}

pub struct EncoderItem {
    pub data: Vec<u8>,
}
pub struct CustomCodec;

impl Encoder<EncoderItem> for CustomCodec {
    type Error = Box<dyn std::error::Error>;

    fn encode(&mut self, item: EncoderItem, dst: &mut bytes::BytesMut) -> Result<(), Self::Error> {
        dst.extend_from_slice(item.data.as_slice());
        Ok(())
    }
}

impl Decoder for CustomCodec {
    type Item = Params;
    type Error = std::io::Error;

    fn decode(&mut self, src: &mut bytes::BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        if !src.is_empty() {
            if let Some(start) = src.windows(2).position(|window| window == [0x55, 0xAA]) {
                if let Some(end) = src.windows(2).position(|window| window == [0x0D, 0x0A]) {
                    if end > start {
                        let frame = src.split_to(end + 2).to_vec();

                        //解析这个frame  将frame 转成 pkgBody;
                        let pkg_header = frame[0..2].to_vec();

                        let pkg_seq = &frame[2];

                        let equ_type = &frame[3];

                        let equ_no = &frame[4];

                        let msg_type = &frame[5];

                        let msg_len = frame[6] as usize;

                        let length = msg_len + 7;

                        let _body = frame[7..length].to_vec();

                        let check_sum = frame[length..length + 2].to_vec();

                        let pkg_tail = frame[length + 2..length + 4].to_vec();

                        let params = Params {
                            pkg_header,
                            pkg_seq: *pkg_seq,
                            equ_type: *equ_type,
                            equ_no: *equ_no,
                            msg_type: *msg_type,
                            msg_len: msg_len.try_into().unwrap(),
                            pkg_body: Default::default(),
                            check_sum,
                            pkg_tail,
                        };

                        Ok(Some(params.to_owned()))
                    } else {
                        Ok(None)
                    }
                } else {
                    Ok(None)
                }
            } else {
                Ok(None)
            }
        } else {
            Ok(None)
        }
    }
}

impl Encoder<Vec<u8>> for CustomCodec {
    type Error = std::io::Error;

    fn encode(&mut self, data: Vec<u8>, dst: &mut bytes::BytesMut) -> Result<(), Self::Error> {
        dst.extend_from_slice(&data);
        Ok(())
    }
}

pub fn to_hex_string(data: &[u8]) -> String {
    hex::encode(data)

    // data.iter()
    //     .map(|b| format!("{:02X}", b))
    //     .collect::<Vec<_>>()
    //     .join("")
}
